package openfeign;

import feign.Logger;
import feign.RequestInterceptor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.openfeign.security.OAuth2FeignRequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Method;
import java.util.regex.Pattern;

import static java.util.Objects.nonNull;
import static java.util.regex.Pattern.CASE_INSENSITIVE;
import static java.util.regex.Pattern.compile;
import static org.springframework.http.HttpHeaders.AUTHORIZATION;
import static org.springframework.util.StringUtils.hasLength;

/**
 * https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html
 */
@Configuration(proxyBeanMethods = false)
@PropertySource("classpath:openfeign-auto.properties")
public class OpenFeignAutoConfiguration {
    static final Pattern BEARER_TOKEN_HEADER_PATTERN = compile("^Bearer (?<token>[a-zA-Z0-9-._~+/]+=*)$", CASE_INSENSITIVE);

    /**
     * @see OAuth2FeignRequestInterceptor
     * @see org.springframework.cloud.openfeign.FeignCircuitBreakerInvocationHandler#asSupplier(Method, Object[])
     * 令牌中继
     * https://blog.csdn.net/qq_35067322/article/details/120878221
     * https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/#oauth2-support
     */
    @Bean
    RequestInterceptor bearerTokenRequestInterceptor() {
        return requestTemplate -> {
            RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
            if (nonNull(requestAttributes) && requestAttributes instanceof ServletRequestAttributes) {
                ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
                String authorizationHeader = servletRequestAttributes.getRequest().getHeader(AUTHORIZATION);
                if (hasLength(authorizationHeader) && BEARER_TOKEN_HEADER_PATTERN.matcher(authorizationHeader).matches()) {
                    requestTemplate.header(AUTHORIZATION); // 先清除 token 头
                    requestTemplate.header(AUTHORIZATION, authorizationHeader);
                }
            }
        };
    }

    /**
     * 这里记录所有，根据实际情况选择合适的日志 Level
     * https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/#feign-logging
     */
    @Bean
    @ConditionalOnMissingBean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}